from datetime import datetime
from django.db import models
from django.db.models import Q

class User(models.Model):
    first_name = models.CharField(max_length=20)
    last_name = models.CharField(max_length=20)
    email = models.CharField(max_length=40)
    ratio = 0

    def get_rate_total(self):
        questions = self.question_set.all()
        q_votes = 0
        for item in questions:
            q_votes += item.votes_num
        answers = self.answer_set.all()
        a_votes = 0
        for item in answers:
            a_votes += item.rating
        return q_votes * 5 + a_votes * 10

    def get_full_name(self):
        return '%s.%s' % (self.first_name, self.last_name)

    def get_short_name(self):
        return self.first_name[0] + self.last_name

    @staticmethod
    def create(email):
        full_name = email.split('@')[0]
        user = User()
        user.email = email
        user.first_name = full_name.split('.')[0]
        user.last_name = full_name.split('.')[-1]
        user.save()
        return user

class Tag(models.Model):
    name = models.CharField(max_length=20)

class Question(models.Model):
    date = models.DateTimeField()
    author = models.ForeignKey(User)
    content = models.CharField(max_length=2000)
    tags = models.ManyToManyField(Tag)
    votes_num = models.IntegerField(default=0)
    voters = models.ManyToManyField(User, related_name='qvoter')
    viewers = models.ManyToManyField(User, related_name='qviewer')
    timestamp = models.DateTimeField()
    aperms = '00'

    def get_answers_num(self):
        return self.answer_set.count()

    def get_answers(self):
        return self.answer_set.order_by('-rating', 'date')

    def get_views_num(self):
        return self.viewers.count()

    def add_viewer(self, user):
        if user not in self.viewers.all():
            self.viewers.add(user)
            self.save()

    def touch(self):
        self.timestamp = datetime.now()
        self.save()

    def has_voter(self, user):
        return user in self.voters.all()

    def set_perms(self, user):
        self.aperms = '11' if user == self.author else '01'
        if self.aperms == '01' and self.has_voter(user):
            self.aperms = '00'

    @staticmethod
    def items_per_page():
        return 10

    @staticmethod
    def get_questions(query, page):
        query = query.strip()
        if len(query) > 0:
            base = Q(content__contains=query)
            key_words = filter(lambda x: x != '', query.split(' '))
            compound = Q(content__contains=key_words[-1])
            for item in key_words[:-1]:
                compound &= Q(content__contains=item)
            questions = Question.objects.filter(base | compound)
        else:
            questions = Question.objects.all()
        questions = questions.order_by('-timestamp')
        quests_count = min(50, questions.count())
        items_per_page = Question.items_per_page()
        pages_count = quests_count / items_per_page
        if quests_count % items_per_page > 0:
            pages_count += 1
        first_item = (page - 1) * items_per_page
        last_item = min(quests_count, page * items_per_page)
        questions = questions[first_item: last_item]
        return questions, pages_count

    @staticmethod
    def get_last(number=1):
        return Question.objects.all().order_by('-timestamp')[:number]

    @staticmethod
    def create(author, content):
        content = content[:min(len(content), 1400)]
        question = Question()
        now = datetime.now()
        question.date = now
        question.author = author
        question.content = content
        question.timestamp = now
        question.save()
        return question

    @staticmethod
    def get_content(question_id):
        question = Question.objects.get(id=question_id)
        return question.content

    @staticmethod
    def update_content(question_id, content):
        content = content[:min(len(content), 1400)]
        question = Question.objects.get(id=question_id)
        question.content = content
        question.save()

    @staticmethod
    def vote_up(question_id, user):
        question = Question.objects.get(id=question_id)
        if user not in question.voters.all():
            question.voters.add(user)
            question.votes_num += 1
            question.save()
        return question.votes_num

    @staticmethod
    def vote_down(question_id, user):
        question = Question.objects.get(id=question_id)
        if user not in question.voters.all():
            question.voters.add(user)
            question.votes_num -= 1
            question.save()
        return question.votes_num

class Answer(models.Model):
    date = models.DateTimeField()
    author = models.ForeignKey(User)
    content = models.CharField(max_length=1500)
    question = models.ForeignKey(Question)
    rating = models.IntegerField(default=0)
    voters = models.ManyToManyField(User, related_name='avoter')
    is_correct = models.BooleanField(default=False)
    aperms = '00'

    def has_voter(self, user):
        return user in self.voters.all()

    def set_perms(self, user):
        self.aperms = '11' if user == self.author else '01'
        if self.aperms == '01' and self.has_voter(user):
            self.aperms = '00'

    @staticmethod
    def create(author, question, content):
        content = content[:min(len(content), 1100)]
        answer = Answer()
        answer.date = datetime.now()
        answer.author = author
        answer.content = content
        answer.question = question
        answer.save()
        return answer

    @staticmethod
    def update_content(answer_id, content):
        content = content[:min(len(content), 1100)]
        answer = Answer.objects.get(id=answer_id)
        answer.content = content
        answer.save()

    @staticmethod
    def vote_up(answer_id, user):
        answer = Answer.objects.get(id=answer_id)
        if user not in answer.voters.all():
            answer.voters.add(user)
            answer.rating += 1
            answer.save()
        return answer.rating

    @staticmethod
    def vote_down(answer_id, user):
        answer = Answer.objects.get(id=answer_id)
        if user not in answer.voters.all():
            answer.voters.add(user)
            answer.rating -= 1
            answer.save()
        return answer.rating